import { type ChunkInfo, type PartInfo, initiateMultipartUpload, uploadPart, completeMultipartUpload, abortMultipartUpload, getKey } from './obs'

export interface VideoUploadOptions {
  file: File
  chunkSize?: number // 分片大小，默认10MB，最小100KB
  onProgress?: (progress: number) => void
  onSuccess?: (path: string) => void
  onError?: (error: any) => void
  signal?: AbortSignal // 取消信号
}

// 分割文件为多个块
function createFileChunks(file: File, chunkSize: number): ChunkInfo[] {
  const chunks: ChunkInfo[] = []
  const totalChunks = Math.ceil(file.size / chunkSize)

  for (let i = 0; i < totalChunks; i++) {
    const start = i * chunkSize
    const end = Math.min(start + chunkSize, file.size)
    const chunk = file.slice(start, end)

    chunks.push({
      chunk,
      partNumber: i + 1, // OBS分段号从1开始
      fileName: `${file.name}.part${i + 1}`,
      totalChunks
    })
  }

  return chunks
}





// 主要的视频上传函数
export async function uploadVideoWithChunks(options: VideoUploadOptions): Promise<void> {
  const { file, chunkSize = 10 * 1024 * 1024, onProgress, onSuccess, onError, signal } = options

  // 确保分片大小至少为100KB（根据OBS文档要求）
  const actualChunkSize = Math.max(chunkSize, 100 * 1024)

  let uploadId: string | null = null
  let objectKey: string | null = null

  try {
    objectKey = getKey(file.name)

    // 分割文件
    const chunks = createFileChunks(file, actualChunkSize)
    console.log(`文件将被分割为${chunks.length}个分片，每片大小约${Math.round(actualChunkSize / 1024 / 1024)}MB`)

    // 检查是否已取消
    if (signal?.aborted) {
      throw new Error('上传已取消')
    }

    // 1. 初始化分段上传任务
    onProgress?.(5) // 初始化进度
    uploadId = await initiateMultipartUpload({ Key: objectKey })

    // 检查是否已取消
    if (signal?.aborted) {
      await abortMultipartUpload({ Key: objectKey, UploadId: uploadId })
      throw new Error('上传已取消')
    }

    // 2. 上传所有分片
    const parts: PartInfo[] = []
    let uploadedChunks = 0

    const updateProgress = () => {
      // 预留5%给初始化，5%给合并，剩余90%为分片上传进度
      const uploadProgress = Math.round((uploadedChunks / chunks.length) * 90)
      onProgress?.(5 + uploadProgress)
    }

    // 并发上传分片（限制并发数避免过多请求）
    const concurrencyLimit = 3
    const maxRetries = 3

    for (let i = 0; i < chunks.length; i += concurrencyLimit) {
      // 检查是否已取消
      if (signal?.aborted) {
        await abortMultipartUpload({ Key: objectKey, UploadId: uploadId })
        throw new Error('上传已取消')
      }

      const batchChunks = chunks.slice(i, i + concurrencyLimit)
      const batchPromises = batchChunks.map(async (chunk) => {
        let retries = 0
        while (retries < maxRetries) {
          // 检查是否已取消
          if (signal?.aborted) {
            throw new Error('上传已取消')
          }

          try {
            const partInfo = await uploadPart({ Key: objectKey!, UploadId: uploadId!, chunkInfo: chunk })
            uploadedChunks++
            updateProgress()
            return partInfo
          } catch (error) {
            retries++
            console.error(`分片${chunk.partNumber}上传失败(第${retries}次重试):`, error)

            if (retries >= maxRetries) {
              throw new Error(`分片${chunk.partNumber}上传失败，已重试${maxRetries}次`)
            }

            // 等待一段时间后重试
            await new Promise(resolve => setTimeout(resolve, 1000 * retries))
          }
        }
        throw new Error(`分片${chunk.partNumber}上传失败`)
      })

      // 等待当前批次完成
      const batchResults = await Promise.all(batchPromises)
      parts.push(...batchResults)
    }

    // 3. 完成分段上传（合并分片）
    onProgress?.(95)
    const finalPath = await completeMultipartUpload({ Key: objectKey!, UploadId: uploadId!, parts: parts })

    onProgress?.(100)
    onSuccess?.(finalPath)

  } catch (error) {
    console.error('视频分段上传失败:', error)

    // 如果上传失败且已经初始化，尝试取消分段上传任务
    if (uploadId && objectKey) {
      try {
        await abortMultipartUpload({ Key: objectKey!, UploadId: uploadId! })
        console.log('已取消失败的分段上传任务')
      } catch (abortError) {
        console.error('取消分段上传任务失败:', abortError)
      }
    }

    onError?.(error)
  }
}

// 检查文件是否为视频类型
export function isVideoFile(file: File): boolean {
  const videoTypes = [
    'video/mp4',
    'video/wmv',
    'video/avi',
    'video/mov',
    'video/flv',
    'video/rmvb',
    'video/3gp',
    'video/m4v',
    'video/mkv'
  ]

  return videoTypes.includes(file.type) ||
    /\.(mp4|wmv|avi|mov|flv|rmvb|3gp|m4v|mkv)$/i.test(file.name)
}

// 获取视频时长（用于显示）
export function getVideoDuration(file: File): Promise<number> {
  return new Promise((resolve, reject) => {
    const video = document.createElement('video')
    video.preload = 'metadata'

    video.onloadedmetadata = () => {
      resolve(video.duration)
      URL.revokeObjectURL(video.src)
    }

    video.onerror = () => {
      reject(new Error('无法读取视频元数据'))
      URL.revokeObjectURL(video.src)
    }

    video.src = URL.createObjectURL(file)
  })
}

// 格式化时长显示
export function formatDuration(seconds: number): string {
  const minutes = Math.floor(seconds / 60)
  const remainingSeconds = Math.floor(seconds % 60)
  return `${minutes}:${remainingSeconds.toString().padStart(2, '0')}`
}

// 根据文件大小计算合理的分片大小
export function calculateOptimalChunkSize(fileSize: number): number {
  // 基础分片大小：5MB
  const baseChunkSize = 5 * 1024 * 1024

  if (fileSize <= 50 * 1024 * 1024) {
    // 小于50MB的文件，使用5MB分片
    return baseChunkSize
  } else if (fileSize <= 500 * 1024 * 1024) {
    // 50MB-500MB的文件，使用10MB分片
    return 10 * 1024 * 1024
  } else if (fileSize <= 2 * 1024 * 1024 * 1024) {
    // 500MB-2GB的文件，使用20MB分片
    return 20 * 1024 * 1024
  } else {
    // 大于2GB的文件，使用50MB分片
    return 50 * 1024 * 1024
  }
}

// 格式化文件大小显示
export function formatFileSize(bytes: number): string {
  if (bytes === 0) return '0 B'

  const k = 1024
  const sizes = ['B', 'KB', 'MB', 'GB']
  const i = Math.floor(Math.log(bytes) / Math.log(k))

  return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i]
} 
